Skip to content

WIP: CPTP instruments#693

Draft
rileyjmurray wants to merge 31 commits intodevelopfrom
cptp-instruments
Draft

WIP: CPTP instruments#693
rileyjmurray wants to merge 31 commits intodevelopfrom
cptp-instruments

Conversation

@rileyjmurray
Copy link
Contributor

@rileyjmurray rileyjmurray commented Dec 3, 2025

This PR adds support for efficient Lindblad parameterizations of quantum instruments. Recall that our model of a quantum instrument is a collection of CPTR (completely positive trace reducing) maps that sum to a CPTP map.

The approach uses a Kraus-polar decomposition. Each CPTR map's Kraus operators are written as K_i = U_i P_i^½, separating into a unitary part and a PSD part. From this point of view, a Kraus-rank-1 channel ρ ↦ K_i ρ K_i^\\dag is a composition of a "root-conj" operator ρ ↦ (P_i^½) ρ (P_i^½) and a unitary channel. Enforcing the trace-preserving sum constraint then amounts to requiring that all PSD factors across all outcomes belong to a single valid POVM, which can be given any of pyGSTi's POVM parameterizations that ensure positivity. The unitaries can be promoted to noisy channels using any gate representation in pyGSTi.

Core changes

Changes to instruments/__init__.py

  • Defines the kraus_polar_instrument function. This is the main entry point to the new functionality.
  • convert delegates to kraus_polar_instrument for Lindblad target types.
  • instrument_type_from_op_type is now a trivial wrapper.

Added a file, modelmembers/operations/cptrop.py, that defines the following pair of linear operator classes used in kraus_polar_instrument.

  • RootConjOperator: implements the map ρ ↦ E^½ ρ E^½, where E is represented by a POVMEffect. Its _rep is recomputed via rootconj_superop() whenever parameters change. Parameters are shared with (and owned by) the underlying effect.
  • SummedOperator: wraps a list of LinearOperators and presents their superoperator sum as a single operator. Used when a CPTR map has Kraus rank > 1.

Changes in tools/optools.py.

  • minimal_kraus_decomposition(op_x, op_basis, ...): returns the shortest list of Kraus operators for a CP superoperator by eigendecomposing its Choi matrix.
  • rootconj_superop(effect_superket, basis, ...): computes the superoperator for ρ ↦ E^½ ρ E^½ given a superket representation of E. Validates that eigenvalues of E lie in [0, 1].
  • superket_trace(superket, basis): returns tr(ρ) given a superket representation of ρ; used in Instrument.acton to compute outcome probabilities correctly for non-PP bases.

Demo notebook

  • Tutorials/objects/advanced/Instruments.ipynb has been substantially revised to demonstrate the new CPTP parameterization alongside the existing TPInstrument workflow.
  • modelpacks/_modelpack.py: extend create_gst_experiment_design to allow custom germs. This is useful for the demo notebook about GST with instruments.

Tests

  • New file test/unit/modelmembers/test_instrument.py: covers Instrument, TPInstrument, RootConjOperator, SummedOperator, and kraus_polar_instrument. Includes round-trip checks (construct -> to_dense -> compare), from_vector/to_vector consistency, and basic acton tests.
  • test/unit/modelmembers/test_operation.py: TPInstrumentOp tests moved from test_operation.py to the new test_instrument.py; test/unit/objects/test_instrument.py removed.

Minor changes

SDPs and diamond distance

  • tools/sdptools.py: adds a new helper, solve_sdp(prob, ...), that wraps the solver-priority loop (MOSEK -> CLARABEL -> CVXOPT) for easy use in different contexts. Returns (objective_val, varvals_dict).
  • Updated diamonddist in optools.py simplified to call solve_sdp.

Almost entirely incidental

  • tools/exceptions.py: added DubiousTargetWarning for alerting users to unusual target specifications.
  • modelmembers/states/cptpstate.py: minor formatting cleanup in deriv_wrt_params; removed a hessian_wrt_params override that was raising NotImplementedError and is now handled by the base class.

Kraus operators in LinearOperator classes.

  • modelmembers/operations/linearop.py: added LinearOperator._kraus_operators() with a default implementation via minimal_kraus_decomposition.
  • modelmembers/operations/denseop.py: replaced the in-line implementation with delegation to LinearOperator._kraus_operators().

@pcwysoc
Copy link
Contributor

pcwysoc commented Dec 9, 2025

The changes to the analysis pipeline do not play nice with reduced models (see error message). I forgot to switch branches and tried to fit a reduced model on a dataset not including instruments. It might make sense to check if there are instruments in the model and only then throw up an error.

Screenshot 2025-12-09 at 1 48 38 PM

@pcwysoc
Copy link
Contributor

pcwysoc commented Dec 9, 2025

Here's the most recent version of my CPTPInstrument which includes Corey's improvements to make it write to and load from disk:
ExampleSavingComposedInst_rev1.ipynb

@pcwysoc
Copy link
Contributor

pcwysoc commented Mar 18, 2026

@rileyjmurray The notebook was shared because at one point you thought it would be useful to have the alternate CPTP Instrument approach documented here. I can't remember why right now. I would just ignore it, as none of the functionality is distinct from functionality already present in this PR.

@rileyjmurray
Copy link
Contributor Author

The notebook was shared because at one point you thought it would be useful to have the alternate CPTP Instrument approach documented here. I can't remember why right now. I would just ignore it, as none of the functionality is distinct from functionality already present in this PR.

@pcwysoc, we had three reasons to be interested in your alternate implementation.

  1. It had clean support for reduced-order Lindblad error generator models and non-CP models. The implementation on this branch fixes most of that, but the way this branch supports non-CP models is different than (and maybe not preferable to) the way done in your notebook.
  2. The parameterization in your notebook seemed to play nicer with pyGSTi's optimizer. IIRC, you needed to tune the optimizer step size using the parameterization on this branch, but you didn't need to do such a thing with your notebook's parameterization.
  3. The notebook parameterization is what's described in the paper.

Given that info, do you still recommend we ignore that branch? In some just just the fact that we've had this conversion on the GitHub PRs serves as documentation in case we want to come back to this, but I figure I'd ask now.

@pcwysoc
Copy link
Contributor

pcwysoc commented Mar 18, 2026

@rileyjmurray answers to your points:

  1. This may be worth considering. My implementation gives access to at least one useful reduced model. Setting the constituent error generator to an 'S' parameterization effectively produces a uniform stochastic instrument. Other models are less useful, as the second order effects of the elementary error generators can become significant and as such not completely remove unwanted FOMGIs.
  2. Both parameterizations experience suboptimal optimizer behavior when ran on the paper data. With my CPTP Instrument implementation, I handled this by running an initial analysis with a TP Instrument, truncating the model to a nearby model with a CPTP Instrument, and using that to seed the CPTP Instrument analysis. I expect both models would benefit from similar adjustments to the optimizer settings.
  3. This is not actually the case. I switched at last minute to your implementation of a CPTP Instrument for forward-compatibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants